package http;

import java.io.IOException;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;

import jk.jni.unrar.NativeRarArchive;
import jk.jni.unrar.NeedPasswordCallBack;
import jk.jni.unrar.NeedPwdCallbackResult;
import jk.jni.unrar.RarFileHeader;
import jk.jni.unrar.RarOpenArchiveData;
import jk.jni.unrar.RarOpenFlag;
import jk.jni.unrar.RarOpenMode;
import jk.jni.unrar.RarOpenResult;
import jk.jni.unrar.RarProcessFileMode;
import jk.jni.unrar.RarReadHeaderResult;
import jk.jni.unrar.RarVolCallBackType;
import jk.jni.unrar.UnRarException;
import jk.jni.unrar.VolumeChangeCallBack;
import jk.jni.unrar.VolumnChangeCallbackResult;

public class PackedPartedDownload extends SubjectImpl implements IObserver {
	private PartedDownload download;
	private String rarExtractor;
	public void setRarExtractor(String rarExtractor) {
		this.rarExtractor = rarExtractor;
	}
	private String targetDirectory;
	private String password;
	public void addDownload(String name,String link) {
		System.out.println("PackedPartedDownload::addDownload("+name+","+link+")");
		download.addDownload(name,link);
	}
	public void setCookies(String cookies) {
		download.setCookies(cookies);
	}
	public void setTargetDirectory(String targetDirectory) {
		this.targetDirectory = targetDirectory;
		download.setTargetDirectory(targetDirectory);
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public PackedPartedDownload() {
		download = new PartedDownload();
	}
	@Override
	public void run() {
		download.addObserver(this);
		download.start();
		System.out.println("PackedPartedDownload::run download.start()");
	}
	public void runUnpackCommand() {
		System.out.println("Starting unpack of File: "+
				download.getDoneDownloads()
				.get(0).getTargetFile().getAbsolutePath()+ " to "+
				targetDirectory);
		String[] s = {
				rarExtractor,
				"e",
				"-p".concat(password),
				"-o+",
				"\""+download.getDoneDownloads()
					.get(0).getTargetFile().getAbsolutePath()+"\"",
				"\""+targetDirectory+"\""
			};
		Process p;
		try {
			p = Runtime.getRuntime().exec(s);
			try {
				if (p.waitFor() == 0) {
					System.out.println("... done! Deleting Files:");
					for (Download singleDownload:download.getDoneDownloads()) {
						System.out.println("File "+singleDownload.getTargetFile().getAbsolutePath()+" ...");
						singleDownload.getTargetFile().delete();
						System.out.println("... deleted!");
					}
				}
				else {
					System.out.println("Could not run the command:");
					for (String param:s)
						System.out.print(param+" ");
					System.out.println();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	public void runUnpackDllCommand() {
		Set<String> sort = new TreeSet<String>();
		for (Download d:download.getDoneDownloads())
			sort.add(d.getTargetFile().getAbsolutePath());

		final Stack<String> fileList = new Stack<String>();
		Stack<String> sortFileList = new Stack<String>();
		for (String s:sort)
			sortFileList.push(s);
		
		while (sortFileList.size() > 0)
			fileList.push(sortFileList.pop());
		
		String firstFile = fileList.pop();
		System.out.println("Unpack starting with "+firstFile);
		RarOpenArchiveData opendata = new RarOpenArchiveData(firstFile,RarOpenMode.RAR_OM_EXTRACT);
		System.out.println("Initializing dll: "+rarExtractor);
		NativeRarArchive.init(rarExtractor);
		System.out.println("Creating RarArchiveObject");
		NativeRarArchive arc = new NativeRarArchive(opendata);
		arc.setVolchgcall(new VolumeChangeCallBack(){
			public VolumnChangeCallbackResult invoke(RarVolCallBackType type, String data) {
				if (type == RarVolCallBackType.RAR_VOL_NOTIFY)
					return VolumnChangeCallbackResult.CONTINUE;
				else {
					String nextHeader = fileList.pop();
					System.out.println("Next Header File: "+nextHeader);
					return new VolumnChangeCallbackResult(nextHeader);
				}
			}			
		});
		final String password = this.password;
		arc.setNeedPwdcall(new NeedPasswordCallBack()
		{
			public NeedPwdCallbackResult invoke() {
				System.out.println("Encryption-Password: "+password);
				return new NeedPwdCallbackResult(password);
			}			
		});
		try {
			System.out.println("Trying to open Archive");
			arc.open();
		} catch (UnRarException ex) {
			ex.printStackTrace();
		}
		
		if (!RarOpenResult.SUCCESS.equals(arc.getOpendata().getOpenResult())){
			
			System.out.println(String.format("open fail!%1$s",arc.getOpendata().getOpenResult().toString()));
			
			return;
		}
		System.out.println(String.format("flag=%1$s,is block encryped:%2$s",opendata.getFlags(),RarOpenFlag.Encrypted.hasFlag(opendata.getFlags())));
		while (RarReadHeaderResult.Success.equals(arc.readHeader())){
			arc.processFile(RarProcessFileMode.RAR_EXTRACT, targetDirectory);
			RarFileHeader header = arc.getCurHeader();
			System.out.println(String.format("header file name:%1$s,is dir:%2$s",header.getFileName(),header.isDirectory()));
		}
		
		arc.close();

	}
	@Override
	public void update(ISubject o) {
		System.out.println("PackedPartedDownload::update() DownloadState of PartedDownload: "+o.getSubjectState());
		if (o.getSubjectState() == 100) {
			//runUnpackDllCommand(); Causes Errors
			runUnpackCommand();
		}
	}
}
